package com.fast.mybatis.mapper.holder;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fast.mybatis.annotation.Table;
import com.fast.mybatis.exception.MapperException;

public class PojoMetaHolder {

	private static final Logger logger = LoggerFactory.getLogger(PojoMetaHolder.class);
	private static Map<String, PojoMeta> pojoMetas = new ConcurrentHashMap<>();

	public  PojoMeta getMeta(Class<?> pojoClz) {
		PojoMeta pojoMeto = pojoMetas.get(pojoClz.getName());
		if(pojoMeto == null || pojoMeto.getTable() == null) {
			pojoMeto = resolve(pojoClz);
			pojoMetas.put(pojoClz.getName(), pojoMeto);
		}
		return pojoMeto;
	}

	public  PojoMeta getPojoMeta(Class<?> clz) {
		if (clz == null || clz.isInterface() || clz == Object.class) {
			return null;
		}
		Class<?> tmp = clz;
		while (tmp != Object.class) {
			PojoMeta m = pojoMetas.get(tmp);
			if (m != null) {
				return m;
			}
			tmp = tmp.getSuperclass();
		}
		return null;
	}

	public  PojoMeta resolve(Class<?> pojoClz) {
		Table table = pojoClz.getAnnotation(Table.class);
		if (table == null) {
			throw new MapperException(pojoClz.getName() +" has no table.");
		}
		
		Map<String, Field> map = new HashMap<>();
		Class<?> clz = pojoClz;
		while (clz != Object.class) {
			Field[] fields = clz.getDeclaredFields();
			for (Field f : fields) {
				map.putIfAbsent(f.getName(), f);
			}
			clz = clz.getSuperclass();
		}
		List<Field> list = new LinkedList<>();
		Collection<Field> set = map.values();
		for (Field f : set) {
			f.setAccessible(true);
			list.add(f);
		}
		if (list.isEmpty()) {
			logger.debug("{}'s column is empty", pojoClz.getName());
			return null;
		}
		
		PojoMeta tm = new PojoMeta(table,pojoClz,list);
		tm.resolve();
		if (tm.getPrimaryList().size() == 0) {
			throw new MapperException(pojoClz.getName() +" has no primary key.");
		}
		return tm;
	}
}
